package com.pwrd.sframe.spring.manager;

import com.pwrd.sframe.spring.annotation.ManagerInject;
import com.pwrd.sframe.spring.annotation.utils.ClassUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Auther syc.
 * @Date 2016/10/24 17:29.
 */
public abstract class Manager {

    //双重校检，懒汉单例
    public volatile static Map<Class<?>, Manager> managers;

    private static void init() {
        Map<Class<?>, Manager> insts = new HashMap<>();

        // 获取源文件夹下的所有类
        Set<Class<?>> classes = ClassUtil.getClassesByPackage("");


        try {
            //存储service类实例
            for (Class<?> clazz : classes) {

                //只添加service(service的子类或者接口的实现类，同时非抽象方法类)
                if (!(Manager.class).isAssignableFrom(clazz) || Modifier.isAbstract(clazz.getModifiers())) {
                    continue;
                }

                Object manager = clazz.newInstance();

                insts.put(clazz, (Manager) manager);
            }

            //注入实例到类中@ManagerInject修饰的成员变量
            for (Class<?> clazz : insts.keySet()) {

                Field[] fields = clazz.getDeclaredFields();

                Manager manager = insts.get(clazz);

                for (Field field : fields) {
                    if (!field.isAnnotationPresent(ManagerInject.class)) {
                        continue;
                    }

                    field.setAccessible(true);

                    if (insts.get(field.getType()) == null) {
                        throw new RuntimeException("This field [" + field + "] of class [" + clazz + "] is not a manager");
                    }

                    field.set(manager, insts.get(field.getType()));
                }

            }

        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

        managers = insts;
    }

    protected Manager() {
    }

    public static <T extends Manager> T getInstance(Class<?> clazz) {

        if(managers == null) {
            synchronized(Manager.class) {
                if(managers == null) {
                    init();
                }
            }
        }

        Manager inst = managers.get(clazz);

        if (inst == null) {
            throw new RuntimeException("获取Manager实例时出错：未能找到对应实例，class=" + clazz);
        }

        return (T) inst;
    }
    public abstract <T> void add(T obj);
}
